package www.dianbaozu.com.ui

import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.bottomnavigation.BottomNavigationItemView
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.netease.nim.uikit.api.NIMHelper
import com.netease.nim.uikit.api.NimUIKit
import com.netease.nim.uikit.business.recent.TeamMemberAitHelper
import com.netease.nim.uikit.xpopup.CreateXPopupHelper
import com.netease.nim.uikit.xpopup.PopupViewEntity
import com.netease.nimlib.sdk.*
import com.netease.nimlib.sdk.Observer
import com.netease.nimlib.sdk.auth.AuthServiceObserver
import com.netease.nimlib.sdk.lifecycle.SdkLifecycleObserver
import com.netease.nimlib.sdk.msg.MsgService
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum
import com.netease.nimlib.sdk.msg.constant.SystemMessageType
import com.netease.nimlib.sdk.msg.model.IMMessage
import com.netease.nimlib.sdk.msg.model.QueryDirectionEnum
import com.netease.nimlib.sdk.msg.model.RecentContact
import com.netease.nimlib.sdk.team.model.Team
import com.xuexiang.xupdate.XUpdate
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import www.dianbaozu.com.R
import www.dianbaozu.com.databinding.FragmentMainBinding
import www.dianbaozu.com.ui.chat.chat.ChatFragment
import www.dianbaozu.com.ui.find.recommendationServer.RecommendationServerFragment
import www.dianbaozu.com.ui.my.MyFragment
import www.dianbaozu.com.ui.server.ServerFragment
import www.wen.com.common.lib.base.fragment.BaseLoadingFragment
import www.wen.com.common.lib.base.module.BaseViewModel
import www.wen.com.common.lib.data.entities.*
import www.wen.com.common.lib.data.network.LAST_VERSION
import www.wen.com.common.lib.extension.*
import www.wen.com.common.lib.helper.loading.KeyHelper
import www.wen.com.common.lib.util.CustomUpdateParser
import www.wen.com.common.lib.util.CustomUpdatePrompter
import www.wen.com.common.lib.util.DisplayUtil
import www.wen.com.common.lib.util.SpUtil
import www.wen.com.common.lib.view.DotView
import java.util.*


/**
 * @author WEN
 * @Description:主页面
 * @date 2020//25 17:48
 */
@AndroidEntryPoint
class MainFragment : BaseLoadingFragment<FragmentMainBinding>(), View.OnClickListener {

    private val mainViewModel: MainViewModel by viewModels()

    var dotViews: MutableList<DotView> = mutableListOf()

    override val viewModel: BaseViewModel
        get() = mainViewModel

    private val mFragments = mutableListOf<Fragment>(
            ServerFragment(),
            ChatFragment(),
            RecommendationServerFragment(),
            MyFragment(),
    )

    private val mMenuIds = intArrayOf(
            R.id.server,
            R.id.chat,
            R.id.find,
            R.id.user
    )

    override fun getLayoutId(): Int = R.layout.fragment_main

    override fun lazyInitView() {
        requestUserInfo()
        updateApp()
        initializeVp()
        clearToast(dataBinding.navigationView, mMenuIds)
        observeLister()
        initUnReadMessageViews()
        requestMessages()
        getAllFriendOnlineStatus()
    }

    private fun initializeVp() {
        dataBinding.vp2.configuration(
                pageLimit = mFragments.size,
                enabledSlide = true,
                provideAdapter = ::provideAdapter,
                action = ::provideRunnable,
                onPageSelectedBA = ::onPageSelected
        )

        dataBinding.navigationView.setOnNavigationItemSelectedListener { item ->
            dataBinding.vp2.setCurrentItem(mMenuIds.indexOfFirst { item.itemId == it }, true)
            true
        }
    }

    private fun observeLister() {
        //云信登录状态的监听,假如被踢出则返回登录页面
        NIMClient.getService(AuthServiceObserver::class.java).observeOnlineStatus(
                { status ->
                    //获取状态的描述
                    if (status.wontAutoLogin()) {
                        toast("您已经在其他设备登录")
                        SpUtil.clearAll()
                        requireActivity().resetStartDestination(R.navigation.navigation, R.id.loginFragment)
                        NIMHelper.logout()
                    }
                }, true)

        //假如token已经无效则返回登录页面
        observeObject(KeyHelper.TOKEN_INVALID_KEY, this, Any::class.java) {
            SpUtil.clearAll()
            requireActivity().resetStartDestination(R.navigation.navigation, R.id.loginFragment)
            NIMHelper.logout()
        }
        //代理导航到目标页面
        observeObject(KeyHelper.NAVIGATION_ID_KEY, this, NavigationEntity::class.java) {
            nav(this.id, this.bundle)
        }
        //代理viewpager切换到目标页面
        observeObject(KeyHelper.MAIN_VIEWPAGER_POSITION_KEY, this, ViewPagePosition::class.java) {
            dataBinding.vp2.currentItem = this.position
        }
        //群组的ait消息
        observeObject(KeyHelper.AIT_MESSAGE, this, AitMessageEntity::class.java) {
        }

        //红点更新
        observeObject(KeyHelper.UNREAD_COUNT_UPDATE, this, Boolean::class.java) {
            dotViews[0].unReadCount = NIMHelper.teamTotalUnreadCount
            dotViews[0].isVisible = NIMHelper.teamTotalUnreadCount > 0
//            dotViews[0].unReadCount = NIMHelper.teamAitMsgTotalUnreadCount
            dotViews[1].unReadCount = NIMHelper.p2pTotalUnreadCount
            dotViews[1].isVisible = NIMHelper.p2pTotalUnreadCount > 0
        }

        //添加好友未读数观察者
        NIMHelper.observeReceiveSystemMsg(true) {
            if (it.type == SystemMessageType.AddFriend) {
                //信息可能是同意好友请求
                if (it.content != getString(R.string.add_friend_msg)) {
                    NIMHelper.setSystemMessageRead(it.messageId)
                } else {
                    NIMHelper.updateAddFriendUnreadCount()
                }
            }
        }

        //消息接收观察者
        NIMHelper.observeReceiveMessage(observer = messageReceiverObserver)

        //最近联系人观察者
        NIMHelper.observeRecentContactList { recents ->
            recents.forEach {
                if (it.sessionType == SessionTypeEnum.Team) {
                    val isMyTeam = NIMHelper.getTeam(it.contactId).isMyTeam
                    if (isMyTeam) {
                        NIMHelper.updateTeamUnreadCount(it.contactId, it.unreadCount)
                    } else {
                        NIMHelper.updateTeamUnreadCount(it.contactId, 0)
                        postObject(KeyHelper.UNREAD_COUNT_UPDATE, true)
                        postObject(KeyHelper.REFRESHING_SERVER_LIST_KEY1, Object())
                    }
                } else if (it.sessionType == SessionTypeEnum.P2P) {
                    NIMHelper.updateP2pUnreadCount(it.contactId, it.unreadCount)
                }
            }
            NIMHelper.updateAddFriendUnreadCount()
        }

        //群移除观察者 无效
//        NIMHelper.observeTeamRemove{
//            NIMHelper.updateTeamUnreadCount(it.id,0)
//            NIMHelper.updateAddFriendUnreadCount()
//        }
    }

    private fun initUnReadMessageViews() {
        //初始化红点view
        var menuView: BottomNavigationMenuView? = null
        for (i in 0 until dataBinding.navigationView.childCount) {
            val child: View = dataBinding.navigationView.getChildAt(i)
            if (child is BottomNavigationMenuView) {
                menuView = child
                break
            }
        }
        if (menuView != null) {
            val dp8: Int = DisplayUtil.dip2px(8f).toInt()
            for (i in 0 until menuView.childCount) {
                val params: FrameLayout.LayoutParams =
                        FrameLayout.LayoutParams(
                                if (i == menuView.childCount - 1) dp8 else dp8 * 2,
                                0
                        )
                params.gravity = Gravity.CENTER_HORIZONTAL
                params.leftMargin = dp8 * 3
                params.topMargin = dp8 / 2
                val itemView: BottomNavigationItemView =
                        menuView.getChildAt(i) as BottomNavigationItemView
                val dotView = DotView(requireActivity())
                dotView.setBackgroundColor(getColorAgency(R.color.colorF04846))
                dotView.setTextColor(getColorAgency(R.color.colorFFFFFF))
                dotView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10f)
                itemView.addView(dotView, params)
                dotView.isVisible = false
                dotViews.add(dotView)
            }
        }
    }

    /**
     * 返回ViewPage2适配器
     */
    private fun provideRunnable(): Runnable {
        return Runnable {
            val item = if (SpUtil.decodeBoolean(KeyHelper.MMKV_IS_FIRST_LOGIN)) 2 else 0
            dataBinding.vp2.currentItem = item
            SpUtil.encode(KeyHelper.MMKV_IS_FIRST_LOGIN, false)
        }
    }

    /**
     * 返回ViewPage2适配器
     */
    private fun provideAdapter(): FragmentStateAdapter {

        return object : FragmentStateAdapter(this) {

            override fun getItemCount(): Int = mFragments.size

            override fun createFragment(position: Int): Fragment = mFragments[position]

        }
    }

    /**
     * 联动
     */
    private fun onPageSelected(page: Int) {
        dataBinding.navigationView.selectedItemId = mMenuIds[page]
    }


    /**
     * 去除长按item自带的toast
     */
    private fun clearToast(bottomNavigationView: BottomNavigationView, ids: IntArray) {
        val bottomNavigationMenuView: ViewGroup = (bottomNavigationView.getChildAt(0) as ViewGroup)
        for (position in ids.indices) {
            bottomNavigationMenuView.getChildAt(position)
                    .findViewById<View>((ids[position] as Int?)!!)
                    .setOnLongClickListener { true }
        }

    }

    private var msgLoaded = false

    private fun requestMessages() {
        lifecycleScope.launch(Dispatchers.IO) {
            delay(250)
            if (msgLoaded) {
                return@launch
            }
            NIMClient.getService(SdkLifecycleObserver::class.java)
                    .observeMainProcessInitCompleteResult(object : Observer<Boolean?> {
                        override fun onEvent(aBoolean: Boolean?) {
                            NIMClient.getService(SdkLifecycleObserver::class.java)
                                    .observeMainProcessInitCompleteResult(this, false)
                            if (msgLoaded) {
                                return
                            }
                            // 把用户加入的所有群都添加进最近联系人里面，否则获取不到未读数
                            NIMHelper.getAllTeam(object : RequestCallbackWrapper<List<Team>?>() {
                                override fun onResult(
                                        code: Int,
                                        result: List<Team>?,
                                        exception: Throwable?,
                                ) {
                                    if (code == ResponseCode.RES_SUCCESS.toInt() && result != null) {
                                        result.forEach {
                                            NIMHelper.createEmptyRecentContact(
                                                    it.id, SessionTypeEnum.Team
                                            )
                                        }
                                    }
                                    // 开始获取未读数
                                    initUnreadCount()
                                }
                            })
                        }
                    }, true)
        }
    }

    private fun initUnreadCount() {
        // 查询最近联系人列表数据
        NIMHelper.getRecentContact(object :
                RequestCallbackWrapper<List<RecentContact>?>() {
            override fun onResult(
                    code: Int,
                    recents: List<RecentContact>?,
                    exception: Throwable?,
            ) {
                if (code != ResponseCode.RES_SUCCESS.toInt() || recents == null) {
                    return
                }
                msgLoaded = true
                //获取对应类型的未读数，并且保存
                val p2pRecents = mutableListOf<RecentContact>()
                recents.forEach {
                    if (it.sessionType == SessionTypeEnum.Team) {
                        NIMHelper.updateTeamUnreadCount(it.contactId, it.unreadCount)
                        updateOfflineContactAited(it)
                    } else if (it.sessionType == SessionTypeEnum.P2P) {
                        NIMHelper.updateP2pUnreadCount(it.contactId, it.unreadCount)
                        p2pRecents.add(it)
                    }
                }
                NIMHelper.updateAddFriendUnreadCount()
                // complete
                /**
                 * 发送事件给[com.netease.nim.uikit.business.recent.RecentContactsFragment]
                 */
                postObject(
                        KeyHelper.P2P_RECENT_CONTACT_UPDATE,
                        RecentContactListEntity(p2pRecents)
                )
            }
        })
    }

    /**
     * 获取群未读信息里面的@消息
     */
    private fun updateOfflineContactAited(recentContact: RecentContact) {
        if (recentContact == null || recentContact.sessionType != SessionTypeEnum.Team || recentContact.unreadCount <= 0) {
            return
        }
        // 锚点
        val uuid: MutableList<String> = ArrayList(1)
        uuid.add(recentContact.recentMessageId)
        val messages =
                NIMClient.getService(MsgService::class.java).queryMessageListByUuidBlock(uuid)
        if (messages == null || messages.size < 1) {
            return
        }
        val anchor = messages[0]
        // 查未读消息
        NIMClient.getService(MsgService::class.java).queryMessageListEx(
                anchor, QueryDirectionEnum.QUERY_OLD,
                recentContact.unreadCount - 1, false
        ).setCallback(object : RequestCallbackWrapper<MutableList<IMMessage>?>() {
            override fun onResult(
                    code: Int,
                    result: MutableList<IMMessage>?,
                    exception: Throwable?,
            ) {
                if (code == ResponseCode.RES_SUCCESS.toInt() && result != null) {
                    result.add(0, anchor)
                    var messageSet: HashSet<IMMessage>? = null
                    // 过滤存在的@我的消息
                    for (msg in result) {
                        if (TeamMemberAitHelper.isAitMessage(msg)) {
                            if (messageSet == null) {
                                messageSet = HashSet()
                            }
                            messageSet.add(msg)
                        }
                    }
                    // 放入messageSet中
                    if (messageSet != null) {
                        NIMHelper.updateTeamAitUnread(recentContact.contactId, messageSet)
                        TeamMemberAitHelper.setRecentContactAited(recentContact, messageSet)
                    }
                }
            }
        })
    }

    //监听在线消息中是否有@我
    private val messageReceiverObserver: Observer<List<IMMessage>?> =
            Observer { imMessages ->
                if (imMessages != null) {
                    for (imMessage in imMessages) {
                        if (!TeamMemberAitHelper.isAitMessage(imMessage)) {
                            continue
                        }
                        NIMHelper.addTeamAitMessage(imMessage)
                    }
                }
            }

    override fun onClick(v: View) {

    }

    private fun updateApp() {
        XUpdate.newBuild(requireActivity())
                .updateUrl(LAST_VERSION)
                .updateParser(CustomUpdateParser())
                .updatePrompter(CustomUpdatePrompter())
                .update()
    }

    @FlowPreview
    fun getAllFriendOnlineStatus() {
        val allFriendAccount = NIMHelper.getAllFriendAccount()
        if (allFriendAccount.isEmpty()) {
            return
        }
        mainViewModel.getUsersOnlineStatus(
                accids = allFriendAccount.toTypedArray(),
                action = {
                    it.data.forEach { userInfo ->
                        NIMHelper.allFriendsLoginStatus[userInfo.accId] = userInfo.onlineStatus
                    }
                    //通知更新
                    NimUIKit.notifyOnlineStateChange(allFriendAccount.toSet())
                })
    }

    /**
     * 获取用户信息,如果用户被封禁则弹窗告知原因
     */
    private fun requestUserInfo() {
        mainViewModel.requestUseInfo { loginInfo ->
            if (loginInfo.forbidStatus) {
                CreateXPopupHelper.createInformPopupView(PopupViewEntity().apply {
                    isShow = true
                    context = requireActivity()
                    title = getString(R.string.the_count_is_ban)
                    content = "因以下原因,用户「${loginInfo.nickName}」 已被封禁：\n\n【${loginInfo.forbidReason}】\n\n在 ${loginInfo.unForbidTime}之前，该账号不能进行登录"
                    confirmContent = getString(R.string.got_it)
                    confirmFunction = {
                        finishMyself()
                    }
                })
            }
        }
    }

}



